package com.gzc.just.play.last.war.sceneserver.benchmark;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.*;
import java.util.concurrent.*;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 消息广播性能基准测试
 * 
 * 测试目标:
 * - 消息广播: 50,000 ops/sec
 * - 平均延迟: < 20μs
 * - 99% 延迟: < 100μs
 */
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(value = 1)
public class MessageBroadcasterBenchmark {
    
    private MessageBroadcaster broadcaster;
    private List<Client> clients;
    private ExecutorService executorService;
    private BlockingQueue<Message> messageQueue;
    
    @BeforeEach
    public void setup() {
        broadcaster = new MessageBroadcaster();
        
        // 初始化客户端
        clients = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            Client client = new Client(2000 + i, "Client" + i);
            clients.add(client);
            broadcaster.addClient(client);
        }
        
        executorService = Executors.newFixedThreadPool(4);
        messageQueue = new LinkedBlockingQueue<>();
    }
    
    @TearDown
    public void tearDown() {
        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
        }
    }
    
    @Benchmark
    public boolean benchmarkMessageUnicast() {
        // 消息单播
        Client targetClient = clients.get(new Random().nextInt(clients.size()));
        Message message = new Message(
            1001, 
            "unicast", 
            "Test unicast message", 
            System.currentTimeMillis()
        );
        
        return broadcaster.sendToClient(targetClient.id, message);
    }
    
    @Benchmark
    public int benchmarkMessageBroadcast() {
        // 消息广播
        Message message = new Message(
            1002,
            "broadcast",
            "Test broadcast message",
            System.currentTimeMillis()
        );
        
        return broadcaster.broadcast(message);
    }
    
    @Benchmark
    public int benchmarkMessageMulticast() {
        // 消息多播（发送给部分客户端）
        List<Integer> targetClients = new ArrayList<>();
        int clientCount = new Random().nextInt(clients.size()) + 1;
        
        // 随机选择目标客户端
        Set<Integer> selected = new HashSet<>();
        while (selected.size() < clientCount) {
            int index = new Random().nextInt(clients.size());
            selected.add(clients.get(index).id);
        }
        targetClients.addAll(selected);
        
        Message message = new Message(
            1003,
            "multicast",
            "Test multicast message",
            System.currentTimeMillis()
        );
        
        return broadcaster.sendToClients(targetClients, message);
    }
    
    @Benchmark
    public int benchmarkBatchMessageBroadcast() {
        // 批量消息广播
        List<Message> messages = new ArrayList<>();
        int messageCount = new Random().nextInt(10) + 1; // 1-10条消息
        
        for (int i = 0; i < messageCount; i++) {
            messages.add(new Message(
                1010 + i,
                "batch_" + i,
                "Batch message " + i,
                System.currentTimeMillis()
            ));
        }
        
        return broadcaster.broadcastBatch(messages);
    }
    
    @Benchmark
    public byte[] benchmarkMessageCompression() {
        // 消息压缩
        Message message = new Message(
            1004,
            "compression_test",
            generateLargeMessageContent(), // 生成较大的消息内容用于测试压缩
            System.currentTimeMillis()
        );
        
        return compressMessage(message);
    }
    
    private String generateLargeMessageContent() {
        // 生成较大的消息内容
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 100; i++) {
            sb.append("This is a large message content for compression testing. ");
        }
        return sb.toString();
    }
    
    private byte[] compressMessage(Message message) {
        // 简化的消息压缩
        String messageString = message.type + ":" + message.content;
        byte[] input = messageString.getBytes();
        
        Deflater compressor = new Deflater();
        compressor.setLevel(Deflater.BEST_COMPRESSION);
        compressor.setInput(input);
        compressor.finish();
        
        byte[] output = new byte[input.length * 2]; // 预留足够空间
        int compressedSize = compressor.deflate(output);
        compressor.end();
        
        byte[] result = new byte[compressedSize];
        System.arraycopy(output, 0, result, 0, compressedSize);
        return result;
    }
    
    @Benchmark
    public void benchmarkAsyncMessageBroadcast() {
        // 异步消息广播
        Message message = new Message(
            1005,
            "async_broadcast",
            "Async broadcast message",
            System.currentTimeMillis()
        );
        
        executorService.submit(() -> {
            broadcaster.broadcast(message);
        });
    }
    
    @Benchmark
    public int benchmarkPrioritizedMessageBroadcast() {
        // 优先级消息广播
        Priority priority = Priority.values()[new Random().nextInt(Priority.values().length)];
        Message message = new Message(
            1006,
            "priority_message",
            "Priority message",
            System.currentTimeMillis(),
            priority
        );
        
        return broadcaster.broadcastWithPriority(message);
    }
    
    @Benchmark
    public boolean benchmarkMessageQueue() {
        // 消息队列处理
        Message message = new Message(
            1007,
            "queue_test",
            "Queue test message",
            System.currentTimeMillis()
        );
        
        return messageQueue.offer(message);
    }
    
    @Benchmark
    public int benchmarkConcurrentMessageBroadcast() {
        // 并发消息广播（模拟多线程环境）
        int threadCount = 4;
        CountDownLatch latch = new CountDownLatch(threadCount);
        int[] results = new int[threadCount];
        
        for (int i = 0; i < threadCount; i++) {
            final int index = i;
            executorService.submit(() -> {
                Message message = new Message(
                    1010 + index,
                    "concurrent_" + index,
                    "Concurrent message " + index,
                    System.currentTimeMillis()
                );
                results[index] = broadcaster.broadcast(message);
                latch.countDown();
            });
        }
        
        try {
            latch.await(1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        return Arrays.stream(results).sum();
    }
    
    // 简化的内部类
    private static class MessageBroadcaster {
        private Map<Integer, Client> clients = new ConcurrentHashMap<>();
        
        public void addClient(Client client) {
            clients.put(client.id, client);
        }
        
        public boolean sendToClient(int clientId, Message message) {
            Client client = clients.get(clientId);
            if (client != null) {
                client.receiveMessage(message);
                return true;
            }
            return false;
        }
        
        public int broadcast(Message message) {
            int sentCount = 0;
            for (Client client : clients.values()) {
                if (client.receiveMessage(message)) {
                    sentCount++;
                }
            }
            return sentCount;
        }
        
        public int sendToClients(List<Integer> clientIds, Message message) {
            int sentCount = 0;
            for (int clientId : clientIds) {
                if (sendToClient(clientId, message)) {
                    sentCount++;
                }
            }
            return sentCount;
        }
        
        public int broadcastBatch(List<Message> messages) {
            int sentCount = 0;
            for (Message message : messages) {
                sentCount += broadcast(message);
            }
            return sentCount;
        }
        
        public int broadcastWithPriority(Message message) {
            // 优先级处理逻辑（简化）
            return broadcast(message);
        }
    }
    
    private static class Client {
        int id;
        String name;
        private List<Message> receivedMessages = new ArrayList<>();
        
        public Client(int id, String name) {
            this.id = id;
            this.name = name;
        }
        
        public boolean receiveMessage(Message message) {
            // 95%概率成功接收消息
            if (Math.random() > 0.05) {
                receivedMessages.add(message);
                return true;
            }
            return false;
        }
    }
    
    private static class Message {
        int id;
        String type;
        String content;
        long timestamp;
        Priority priority;
        
        public Message(int id, String type, String content, long timestamp) {
            this(id, type, content, timestamp, Priority.NORMAL);
        }
        
        public Message(int id, String type, String content, long timestamp, Priority priority) {
            this.id = id;
            this.type = type;
            this.content = content;
            this.timestamp = timestamp;
            this.priority = priority;
        }
    }
    
    private enum Priority {
        LOW, NORMAL, HIGH, CRITICAL
    }
    
    /**
     * JUnit 测试方法 - 验证基准测试是否可以正常工作
     */
    @Test
    public void testMessageBroadcastSetup() {
        // 测试设置是否正确
        assertNotNull(broadcaster, "Message broadcaster should not be null");
        assertNotNull(clients, "Clients should not be null");
        assertFalse(clients.isEmpty(), "Clients should not be empty");
        assertNotNull(messageQueue, "Message queue should not be null");
        
        // 测试方法可以正常运行
        boolean unicastResult = benchmarkMessageUnicast();
        assertTrue(unicastResult, "Message unicast should succeed");
        
        int broadcastResult = benchmarkMessageBroadcast();
        assertTrue(broadcastResult > 0, "Message broadcast should succeed");
        
        byte[] compressed = benchmarkMessageCompression();
        assertNotNull(compressed, "Message compression should not return null");
        assertTrue(compressed.length > 0, "Compressed message should not be empty");
        
        boolean queued = benchmarkMessageQueue();
        assertTrue(queued, "Message should be queued successfully");
    }
    
    /**
     * JUnit 测试方法 - 验证基准测试方法的性能
     */
    @Test
    public void testMessageBroadcastPerformance() {
        // 初始化测试数据
        setup();
        
        // 测试消息单播性能
        long startTime = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            benchmarkMessageUnicast();
        }
        long duration = System.nanoTime() - startTime;
        
        // 验证在合理时间内完成（1秒内）
        assertTrue(duration < 1_000_000_000L, 
            "Message unicast should complete within 1 second");
        
        // 测试消息广播性能
        startTime = System.nanoTime();
        for (int i = 0; i < 100; i++) {
            benchmarkMessageBroadcast();
        }
        duration = System.nanoTime() - startTime;
        
        // 验证在合理时间内完成（1秒内）
        assertTrue(duration < 1_000_000_000L, 
            "Message broadcast should complete within 1 second");
    }
}